﻿using ACC.Business;
using ACC.Business.Process;
using ACC.Business.Stn;
using ACC.Data;
using ACC.Data.Comm;
using ACC.Data.Entities.Common;
using ACC.Data.Line;
using ACC.Device;
using ACC.Device.ACCComm;
using ACC.Device.Common;
using ACC.Interface.Implement;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ACC.Interface.Extensions
{
    public static class ACCExt
    {
        public static ProcessRework GetReworkProcess(this StnProcess stnProcess)
        {
            return (ProcessRework)XmlCommand.commandList["rework"];
        }

        public static ACCCode ReadLoginParam(this ACCDevice device, ACCDevice dev, out string operatorId)
        {
            operatorId = string.Empty;

            return ACCCode.ACCOK;
        }

        public static ACCCode SendLoginResult(this ACCDevice device, string oprid)
        {
            return ACCCode.ACCOK;
        }

        public static ACCCode SendLogoutResult(this ACCDevice device, string oprid)
        {
            return ACCCode.ACCOK;
        }

        public static void SetLotChangeData(this ACCDevice device, List<ACCDevice.LotChangeData> datas)
        {
            if (device is ClientCommonDevice)
            {
                (device as ClientCommonDevice).LastLotChangeDatas = datas;
            }
        }

        public static ACCDevice.LotChangeResult GetLotChangeResult(this ACCDevice device)
        {
            if (device is ClientCommonDevice)
            {
                return (device as ClientCommonDevice).LastLotChangeResult;
            }

            return new ACCDevice.LotChangeResult() { ErrorCode = ACCCode.ACCInternalError };
        }

        public static BomItemCfg GetMainBomItem(this StnProcess stnProcess)
        {
            if (stnProcess != null && stnProcess._data != null)
            {
                if (stnProcess._data.Variables.ContainsKey("MainBomItemCfg") &&
                    stnProcess._data.Variables["MainBomItemCfg"] is BomItemCfg)
                {
                    return stnProcess._data.Variables["MainBomItemCfg"] as BomItemCfg;
                }
            }

            return null;
        }

        public static BomItemCfg[] GetBomItems(this StnProcess stnProcess)
        {
            if (stnProcess != null && stnProcess._data != null)
            {
                if (stnProcess._data.Variables.ContainsKey("BomItemCfgs") &&
                    stnProcess._data.Variables["BomItemCfgs"] is BomItemCfg[])
                {
                    return stnProcess._data.Variables["BomItemCfgs"] as BomItemCfg[];
                }
            }

            return new BomItemCfg[] { };
        }

        public static List<string> GetTempVariablesByKey(this StnProcess stnProcess, string varKey)
        {
            List<string> lstValues = new List<string>();
            var dt = ACC.Data.DataManager.DBHelper.Query("SELECT VARKEY,VARVALUE FROM ACC_TEMP_VARIABLES WHERE VARKEY='" + varKey + "'");
            if (dt != null && dt.Rows.Count > 0)
            {
                foreach (System.Data.DataRow row in dt.Rows)
                {
                    lstValues.Add(row["VARVALUE"].ToString());
                }
            }

            return lstValues;
        }

        public static string GetTempVariablesByValue(this StnProcess stnProcess, string varValue, ref List<string> lstValues)
        {
            string key = string.Empty;

            if (lstValues == null)
                lstValues = new List<string>();

            var dt = ACC.Data.DataManager.DBHelper.Query("SELECT VARKEY,VARVALUE FROM ACC_TEMP_VARIABLES WHERE VARKEY  IN (SELECT VARKEY FROM ACC_TEMP_VARIABLES WHERE VARVALUE = '" + varValue + "')");
            if (dt != null && dt.Rows.Count > 0)
            {
                foreach (System.Data.DataRow row in dt.Rows)
                {
                    lstValues.Add(row["VARVALUE"].ToString());
                }

                key = dt.Rows[0]["VARKEY"].ToString();
            }

            return key;
        }

        public static int RemoveTempVariablesByKey(this StnProcess stnProcess, string varKey)
        {
            return ACC.Data.DataManager.DBHelper.Update("DELETE FROM ACC_TEMP_VARIABLES WHERE VARKEY='" + varKey + "'");
        }

        public static int RemoveTempVariablesByValue(this StnProcess stnProcess, string varValue)
        {
            return ACC.Data.DataManager.DBHelper.Update("DELETE FROM ACC_TEMP_VARIABLES WHERE VARKEY IN (SELECT VARKEY FROM ACC_TEMP_VARIABLES WHERE VARVALUE='" + varValue + "')");
        }

        public static bool AddTempVariables(this StnProcess stnProcess, string varKey, List<string> lstValues)
        {
            if (string.IsNullOrEmpty(varKey) || lstValues == null || lstValues.Count <= 0)
                return false;

            var conn = ACC.Data.DataManager.DBHelper.GetConnection(ACC.Util.DB.DBHelper.DEFAULT);
            var trans = conn.BeginTransaction();
            try
            {
                foreach (string varValue in lstValues.ToArray())
                {
                    ACC.Data.DataManager.DBHelper.Update(trans, "INSERT INTO ACC_TEMP_VARIABLES(VARKEY, VARVALUE) VALUES('" + varKey + "','" + varValue + "')");
                }
                trans.Commit();
                return true;
            }
            catch (Exception ex)
            {
                trans.Rollback();
                stnProcess.logger.Debug(ex.Message + "\r\n" + ex.StackTrace);
            }
            finally
            {
                if (conn != null && conn.State == System.Data.ConnectionState.Open)
                {
                    conn.Close();
                }
                conn = null;
            }

            return false;
        }

        /// <summary>
        /// 去除托盘号和条码的关联关系
        /// 内存中关联关系也移除
        /// </summary>
        /// <param name="stnProcess"></param>
        /// <param name="palletNo"></param>
        /// <returns></returns>
        public static int RemovePallet(this StnProcess stnProcess, string palletNo)
        {
            var v = stnProcess._data.StnCfg.LineCfg.LineData.RunningData.Variables;
            if (v != null && v.ContainsKey("PALLET-" + palletNo))
            {
                v.Remove("PALLET-" + palletNo);
            }
            return DataManager.DBHelper.Update(string.Format("DELETE FROM ACC_PALLETS WHERE PALLETNO='{0}'", palletNo));
        }

        /// <summary>
        /// 取Pallet 关联的条码信息
        /// 先从内存取，避免太多的数据库查询
        /// </summary>
        /// <param name="stnProcess"></param>
        /// <param name="palletNo"></param>
        /// <returns></returns>
        public static string[] GetPallet(this StnProcess stnProcess, string palletNo)
        {
            string[] strRet = null;
            var v = stnProcess._data.StnCfg.LineCfg.LineData.RunningData.Variables;
            if (v != null && v.ContainsKey("PALLET-" + palletNo))
            {
                var pallet = (Pallet)v["PALLET-" + palletNo];
                if (pallet != null)
                {
                    strRet = new string[3];
                    strRet[0] = pallet.SN1;
                    strRet[1] = pallet.SN2;
                    strRet[2] = pallet.SN3;

                    return strRet;
                }
            }

            var dt = DataManager.DBHelper.Query(string.Format("SELECT SN1,SN2,SN3 FROM ACC_PALLETS WHERE PALLETNO='{0}'", palletNo));
            if (dt != null && dt.Rows.Count > 0)
            {
                strRet = new string[3];
                strRet[0] = dt.Rows[0]["SN1"].ToString();
                strRet[1] = dt.Rows[0]["SN2"].ToString();
                strRet[2] = dt.Rows[0]["SN3"].ToString();

                v["PALLET-" + palletNo] = new Pallet()
                {
                    LINE = stnProcess._data.StnCfg.LineCfg.Line,
                    PALLETNO = palletNo,
                    SN1 = strRet[0],
                    SN2 = strRet[1],
                    SN3 = strRet[2],
                    CTime = DateTime.Now
                };
            }

            return strRet;
        }

        /// <summary>
        /// 获取条码关联的托盘号
        /// 先从内存取，取不到再从数据库取，避免太多的数据库查询
        /// </summary>
        /// <param name="stnProcess"></param>
        /// <param name="sn1"></param>
        /// <returns></returns>
        public static string GetPalletBySN1(this StnProcess stnProcess, string sn1)
        {
            var v = stnProcess._data.StnCfg.LineCfg.LineData.RunningData.Variables;
            var val = v == null ? null : v.Values.FirstOrDefault(c => c is Pallet && (c as Pallet).SN1 == sn1);
            if(val != null)
            {
                return (val as Pallet).PALLETNO;
            }

            string strRet = "";
            var dt = DataManager.DBHelper.Query(string.Format("SELECT PALLETNO FROM ACC_PALLETS WHERE SN1 = '{0}'", sn1));
            if (dt != null && dt.Rows.Count > 0)
            {
                strRet = dt.Rows[0]["PALLETNO"].ToString();
            }

            return strRet;
        }

        /// <summary>
        /// 关联托盘号和对应的条码
        /// 同事放在内存中，避免后面太多的数据库查询
        /// </summary>
        /// <param name="stnProcess"></param>
        /// <param name="palletNo"></param>
        /// <param name="sn1"></param>
        /// <param name="sn2"></param>
        /// <param name="sn3"></param>
        /// <param name="line">为空则默认当前线</param>
        /// <returns></returns>
        public static bool AddPallet(this StnProcess stnProcess, string palletNo, string sn1, string sn2, string sn3, string line)
        {
            if (string.IsNullOrEmpty(palletNo))
                return false;

            if (string.IsNullOrEmpty(line))
                line = stnProcess._data.StnCfg.LineCfg.Line;

            if (!LineManager.LineDatas.ContainsKey(line))
                return false;

            try
            {
                var v = LineManager.LineDatas[line].RunningData.Variables;
                var pallet = v == null ? null : (v.ContainsKey("PALLET-" + palletNo) ? (Pallet)v["PALLET-" + palletNo] : null);
                pallet = pallet == null ? new Pallet()
                {
                    PALLETNO = palletNo,
                    LINE = line,
                    CTime = DateTime.Now
                } : pallet;

                pallet.SN1 = sn1;
                pallet.SN2 = sn2;
                pallet.SN3 = sn3;
                v["PALLET-" + palletNo] = pallet;

                string sql = string.Format("UPDATE ACC_PALLETS SET SN1='{0}', SN2='{1}', SN3='{2}', CTime='{4}', LINE='{5}' WHERE PALLETNO='{3}' ",
                                    sn1, sn2, sn3, palletNo, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), line);
                if (DataManager.DBHelper.Update(sql) < 1)
                {
                    sql = string.Format("INSERT INTO ACC_PALLETS(PALLETNO, SN1, SN2, SN3, CTime, LINE) VALUES('{0}','{1}', '{2}', '{3}', '{4}', '{5}')",
                                palletNo, sn1, sn2, sn3, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), line);
                    return DataManager.DBHelper.Update(sql) > 0;
                }
            }
            catch (Exception ex)
            {
                stnProcess.logger.Debug(ex.Message + "\r\n" + ex.StackTrace);
            }

            return false;
        }

        /// <summary>
        /// 关联托盘号和对应的条码
        /// </summary>
        /// <param name="stnProcess"></param>
        /// <param name="palletNo"></param>
        /// <param name="sn1"></param>
        /// <param name="sn2"></param>
        /// <param name="sn3"></param>
        /// <returns></returns>
        public static bool AddPallet(this StnProcess stnProcess, string palletNo, string sn1, string sn2, string sn3)
        {
            return AddPallet(stnProcess, palletNo, sn1, sn2, sn3, string.Empty);
        }

        static string SQL_BIN_UPDATE = "UPDATE ACC_Material_Bin SET ItemPartNo='{0}', Lot='{1}', Qty={2}, CTime='{3}' WHERE Bin='{4}' AND ItemPartNo='{0}'";
        static string SQL_BIN_INSERT = "INSERT INTO ACC_Material_Bin(ItemPartNo, Bin, Lot, Qty, USN, CTime) VALUES('{0}', '{1}', '{2}', {3}, '{4}', '{5}')";
        static string SQL_BIN_SELECT = "SELECT * FROM ACC_Material_Bin WHERE BIN='{0}'";
        static string SQL_BIN_DELETE = "DELETE FROM ACC_Material_Bin WHERE BIN='{0}'";
        public static int AddLotByBin(this StnProcess stnProcess, string bin, ClientLotTrackItem lotItem)
        {
            int nRet = 0;
            if (lotItem != null)
            {
                try
                {
                    nRet = ACC.Data.DataManager.DBHelper.Update(string.Format(SQL_BIN_UPDATE, lotItem.ItemPartNo, lotItem.Lot, lotItem.Qty, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), bin));
                    if (nRet <= 0)
                    {
                        nRet = ACC.Data.DataManager.DBHelper.Update(string.Format(SQL_BIN_INSERT, lotItem.ItemPartNo, bin, lotItem.Lot, lotItem.Qty, lotItem.USN, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
                    }
                }
                catch (Exception ex)
                {
                    nRet = -1;
                    stnProcess.logger.Debug(ex.Message + "\r\n" + ex.StackTrace);
                }
            }

            return nRet;
        }

        public static int AddLotByBin(this StnProcess stnProcess, string bin, List<ClientLotTrackItem> lotItems)
        {
            int nRet = 0;
            if (lotItems != null && lotItems.Count > 0)
            {
                var conn = ACC.Data.DataManager.DBHelper.GetConnection(ACC.Util.DB.DBHelper.DEFAULT);
                var trans = conn.BeginTransaction();
                try
                {
                    ACC.Data.DataManager.DBHelper.Update(trans, string.Format(SQL_BIN_DELETE, bin));
                    foreach (ClientLotTrackItem lotItem in lotItems)
                    {
                        int ret = ACC.Data.DataManager.DBHelper.Update(trans, string.Format(SQL_BIN_INSERT, lotItem.ItemPartNo, bin, lotItem.Lot, lotItem.Qty, lotItem.USN, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
                        nRet += (ret >= 0 ? ret : 0);
                    }
                    trans.Commit();
                }
                catch (Exception ex)
                {
                    nRet = -1;
                    trans.Rollback();
                    stnProcess.logger.Debug(ex.Message + "\r\n" + ex.StackTrace);
                }
                finally
                {
                    if (conn != null && conn.State == System.Data.ConnectionState.Open)
                    {
                        conn.Close();
                    }
                    conn = null;
                }
            }

            return nRet;
        }

        public static List<ClientLotTrackItem> GetLotByBin(this StnProcess stnProcess, string bin)
        {
            List<ClientLotTrackItem> lotItems = new List<ClientLotTrackItem>();
            try
            {
                var dt = ACC.Data.DataManager.DBHelper.Query(string.Format(SQL_BIN_SELECT, bin));
                if (dt != null && dt.Rows.Count > 0)
                {
                    foreach (System.Data.DataRow row in dt.Rows)
                    {
                        String itemPartNo = dt.Rows[0]["ItemPartNo"].ToString();
                        String itemRev = dt.Rows[0]["ItemRev"] == null ? "" : dt.Rows[0]["ItemRev"].ToString();
                        String sLot = dt.Rows[0]["SLot"] == null ? "" : dt.Rows[0]["SLot"].ToString();
                        String usn = dt.Rows[0]["USN"] == null ? "" : dt.Rows[0]["USN"].ToString();
                        String lot = dt.Rows[0]["Lot"].ToString();
                        String qty = dt.Rows[0]["Qty"].ToString();

                        lotItems.Add(new ClientLotTrackItem() { ItemPartNo = itemPartNo, ItemRev = itemRev, Lot = lot, SLot = sLot, USN = usn, Qty = qty });

                    }
                }
            }
            catch (Exception ex)
            {
                stnProcess.logger.Debug(ex.Message + "\r\n" + ex.StackTrace);
            }

            return lotItems;
        }

        public static bool IsSameSegment(this StnProcess stnProcess, RoutingSetpCfg route1, RoutingSetpCfg route2)
        {
            if (route1 != null &&
                route2 != null &&
                route1.Status != RoutingSetpCfg.RoutingCfgStatus.StandalongSubStation &&
                route2.Status != RoutingSetpCfg.RoutingCfgStatus.StandalongSubStation)
            {
                if (route1.Segment == null && route2.Segment == null)
                    return true;

                if (route1.Segment != null &&
                    route2.Segment != null &&
                    route1.Segment.SegmentCode == route2.Segment.SegmentCode)
                    return true;
            }

            return false;
        }


        // 用于处理同一组件(IDName)在不同工位装配，且有可能不同工位装配的数量不一致的情况，克隆一个BomItemCfg
        public static BomItemCfg CloneBomItemCfg(this StnProcess stnProcess, RuningPartNo partNo, string idName)
        {
            BomItemCfg item = null;
            if (partNo != null && !string.IsNullOrEmpty(idName))
            {
                item = partNo.BomCfg.GetBomItemCfgByIDName(idName);
                if (item != null)
                {
                    item = item.Clone();
                    item.QtyPer = 1;
                    string sql = "SELECT QTY_PER,IDPATTERN FROM ACC_BOMITEM_SETUP WHERE LINE='{0}' AND OP='{1}' AND PARTNO='{2}' AND IDNAME='{3}'";
                    DataTable dt = DataManager.DBHelper.Query(string.Format(sql, stnProcess._data.StnCfg.LineCfg.LineData.Line, stnProcess._data.StnCfg.OPCfg.OP, partNo.BomCfg.PartNo, idName));
                    if (dt != null && dt.Rows.Count > 0)
                    {
                        item.QtyPer = (int)(double.Parse(dt.Rows[0]["QTY_PER"] is DBNull ? "1" : dt.Rows[0]["QTY_PER"].ToString()));
                        item.IDPattern = dt.Rows[0]["IDPATTERN"] is DBNull ? "1" : dt.Rows[0]["IDPATTERN"].ToString();
                    }
                }
            }
            return item;
        }

        public static List<ClientBomItems> GetBomItemCfg(this StnProcess stnProcess)
        {
            var lstBoms = new List<ClientBomItems>();
            BomItemCfg mainItemCfg = null;
            if (stnProcess._data.IsFirstStn && stnProcess._data.Components.Length > 0)
            {
                mainItemCfg = stnProcess._data.Components[0];
            }
            else
            {
                var a = stnProcess._data.Route.LineRoutingCfg.RoutingCfg.FirstOrDefault(c => (stnProcess.IsSameSegment(c.Value, stnProcess._data.Route) && c.Value.Status == RoutingSetpCfg.RoutingCfgStatus.Start));
                if (!default(KeyValuePair<OPCfg, RoutingSetpCfg>).Equals(a))
                {
                    if (stnProcess._data.PartNo != null)
                    {
                        var v = stnProcess._data.PartNo.BomCfg.BomItemCfg.FirstOrDefault(c => c.Key.OP == a.Key.OP);
                        if (!default(KeyValuePair<OPCfg, ACC.Data.Line.BomCfg.OPBomCfg>).Equals(v))
                        {
                            mainItemCfg = v.Value.BomItem.Values.FirstOrDefault(c => c.LeadNo);
                        }
                    }
                    if (mainItemCfg == null)
                    {
                        var o = stnProcess._data.StnCfg.LineCfg.LineData.RunningData.OPDatas.FirstOrDefault(c => c.Key.OP == a.Key.OP);
                        if (!default(KeyValuePair<OPCfg, OPRunningData>).Equals(o))
                        {
                            foreach (StnRunningData stn in o.Value.StnDatas.Values.ToArray())
                            {
                                if (stn != null && stn.Components.Length > 0)
                                {
                                    mainItemCfg = stn.Components[0];
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            BomItemCfg[] stnBomItemCfgs = stnProcess.GetBomItems();
            stnBomItemCfgs = (stnBomItemCfgs != null && stnBomItemCfgs.Length > 0) ? stnBomItemCfgs : stnProcess._data.Components;
            if (stnBomItemCfgs != null && stnBomItemCfgs.Length > 0)
            {
                for (int index = (stnProcess._data.IsFirstStn ? 1 : 0); index < stnBomItemCfgs.Length; index++)
                {
                    lstBoms.Add(new ClientBomItems()
                    {
                        PartNo = stnBomItemCfgs[index].BomCfg.PartNo,
                        Rev = stnBomItemCfgs[index].BomCfg.Rev,
                        ItemPartNo = stnBomItemCfgs[index].ItemPartNo,
                        ItemRev = stnBomItemCfgs[index].ItemRev,
                        IDName = stnBomItemCfgs[index].IDName,
                        IDPattern = stnBomItemCfgs[index].IDPattern,
                        Description = stnBomItemCfgs[index].DescLocal,
                        Qty = stnBomItemCfgs[index].QtyPer.ToString(),
                        Sequence = index,
                        OP=stnBomItemCfgs[index].op,
                        LeadNo = stnBomItemCfgs[index].LeadNo
                    });
                }
            }

            BomItemCfg stnMainBomItemCfg = stnProcess.GetMainBomItem();
            mainItemCfg = stnMainBomItemCfg != null ? stnMainBomItemCfg : mainItemCfg;
            if (mainItemCfg != null)
            {
                //将主条码置顶
               // lstBoms.Add(new ClientBomItems()
                lstBoms.Insert(0,new ClientBomItems()
                {
                    PartNo = mainItemCfg.BomCfg.PartNo,
                    Rev = mainItemCfg.BomCfg.Rev,
                    ItemPartNo = mainItemCfg.ItemPartNo,
                    ItemRev = mainItemCfg.ItemRev,
                    IDName = mainItemCfg.IDName,
                    IDPattern = mainItemCfg.IDPattern,
                    Description = mainItemCfg.DescLocal,
                    Qty = stnProcess._data.IsFirstStn ? mainItemCfg.QtyPer.ToString() : "1",
                    //Qty = mainItemCfg.QtyPer.ToString(),
                    Sequence = stnProcess._data.IsFirstStn ? stnProcess._data.Components.Length : stnProcess._data.Components.Length + 1,
                    OP = mainItemCfg.op,
                    LeadNo = mainItemCfg.LeadNo
                });

            }

            return lstBoms;
        }

        public static List<ClientLotTrackItem> GetComponentSet(this StnProcess stnProcess, bool isAllComps)
        {
            var listCompSet = new List<ClientLotTrackItem>();
            var compSet = stnProcess._data.GetComponentSet(stnProcess._data.PartNo);
            if (compSet != null)
            {
                //var items = compSet.Items.Values.Where(c =>
                //    c.BomItem.LotTrack && (isAllComps || c.LotItem.OP == stnProcess._data.StnCfg.OPCfg.OP));

                var items = compSet.Items.Values.Where(c =>
                    c.BomItem.LotTrack && (isAllComps || c.BomItem.op == stnProcess._data.StnCfg.OPCfg.OP));

                foreach (ComponentSetItem item in items)
                {
                    listCompSet.Add(new ClientLotTrackItem()
                    {
                        ItemPartNo = item.BomItem.ItemPartNo,
                        ItemRev = item.BomItem.ItemRev,
                        Description = item.BomItem.Desc,
                        Qty = item.LotItem == null ? "0" : item.LotItem.Qty.ToString(),
                        Lot = item.LotItem == null ? "" : item.LotItem.Lot,
                        SLot = item.LotItem == null ? "" : item.LotItem.Supplier_Lot,
                        FeederNo = item.LotItem == null ? "" : item.LotItem.FeederNO,
                        USN = item.LotItem == null ? "" : item.LotItem.Reserved
                    });
                }
            }

            return listCompSet;
        }

        public static List<ClientFailureBit> GetFailureBitsCfg(this StnProcess stnProcess, BomCfg bomCfg)
        {
            var lstFailreBits = new List<ClientFailureBit>();
            var statusCfgList = stnProcess._data.StnCfg.StnStatusWordCfg[bomCfg];
            if (statusCfgList != null)
            {
                foreach (int bit in statusCfgList.Keys.ToArray())
                {
                    if (bit != 0 && statusCfgList[bit].Type == StatusWordType.FailureWord)
                    {
                        DataTable dt = DataManager.DBHelper.Query("SELECT * FROM ACC_PARTTYPE_STATUSBIT_CFG WHERE BIT <> 0 AND REC_ID=" + statusCfgList[bit].RecID);
                        if (dt != null && dt.Rows.Count > 0)
                        {
                            foreach (DataRow row in dt.Rows)
                            {
                                lstFailreBits.Add(new ClientFailureBit()
                                {
                                    Bit = int.Parse(row["BIT"].ToString()) + 1,
                                    Description = row["DESCRIPTION"] is DBNull ? "" : row["DESCRIPTION"].ToString()
                                });
                            }
                            break;
                        }
                    }
                }
            }

            return lstFailreBits;
        }

        public static List<ClientFailureWord> GetFailureWordCfg(this StnProcess stnProcess, BomCfg bomCfg, bool isAllBits = false )
        {
            List<ClientFailureWord> lstFailureWords = new List<ClientFailureWord>();
            DictionaryEx<int, PartTypeStatusWordCfg> statusCfgList = stnProcess._data.StnCfg.StnStatusWordCfg[bomCfg];
            if (statusCfgList != null)
            {
                foreach (int bit in statusCfgList.Keys.ToArray())
                {
                    if (bit != 0 && statusCfgList[bit].Type == StatusWordType.FailureWord)
                    {
                        List<ClientFailureBit> lstFailureBits = new List<ClientFailureBit>();
                        DataTable dt = DataManager.DBHelper.Query("SELECT * FROM ACC_PARTTYPE_STATUSBIT_CFG WHERE " + (isAllBits ? "" : " BIT <> 0 AND ") + " REC_ID=" + statusCfgList[bit].RecID);
                        if (dt != null && dt.Rows.Count > 0)
                        {
                            foreach (DataRow row in dt.Rows)
                            {
                                lstFailureBits.Add(new ClientFailureBit()
                                {
                                    Bit = int.Parse(row["BIT"].ToString()),
                                    Description = row["DESCRIPTION"] is DBNull ? "" : row["DESCRIPTION"].ToString(),
                                    Name = statusCfgList[bit].Name
                                });
                            }
                        }

                        lstFailureWords.Add(new ClientFailureWord()
                        {
                            Name = statusCfgList[bit].Name,
                            Description = statusCfgList[bit].Description,
                            PLC_NAME = statusCfgList[bit].PLCName,
                            PLC_TAG_ADDR = statusCfgList[bit].PLCTagAddr,
                            StatusBits = lstFailureBits
                        });
                    }
                }
            }

            return lstFailureWords;
        }

        public static List<ClientParttypeTagCfg> GetPartTypeTagCfg(this StnProcess stnProcess, BomCfg bomCfg)
        {
            List<ClientParttypeTagCfg> lstPartTypeTagCfg = new List<ClientParttypeTagCfg>();
            if (bomCfg.ParttypeTagList != null && bomCfg.ParttypeTagList.Values != null)
            {
                foreach (ParttypeTagCfg partTypeTagCfg in bomCfg.ParttypeTagList.Values.ToArray())
                {
                    if (partTypeTagCfg != null)
                    {
                        lstPartTypeTagCfg.Add(new ClientParttypeTagCfg()
                        {
                            Name = partTypeTagCfg.Name,
                            Description = partTypeTagCfg.Description,
                            Value = partTypeTagCfg.Value
                        });
                    }
                }
            }

            return lstPartTypeTagCfg;
        }

        static Regex INT_PATTERN = new Regex("INT\\[(\\d+)\\]", RegexOptions.IgnoreCase);
        static Regex REAL_PATTERN = new Regex("REAL\\[(\\d+)\\]", RegexOptions.IgnoreCase);
        static Regex BOOL_PATTERN = new Regex("BOOL\\[(\\d+)\\]", RegexOptions.IgnoreCase);
        static Regex STRING_PATTERN = new Regex("STRING\\[(\\d+)\\]", RegexOptions.IgnoreCase);

        public static List<ClientProcData> GetProcessDataCfg(this StnProcess stnProcess, BomCfg bomCfg, uint his_id)
        {
            LineData lineData = stnProcess._data.StnCfg.LineCfg.LineData;
            List<ClientProcData> lstProcData = new List<ClientProcData>();
            DictionaryEx<String, ProcDataCfg> procdatacfg = stnProcess._data.StnCfg.StnPLCProcDataCfg[bomCfg];
            if (his_id > 0)
            {
                var dt = DataManager.DBHelper.Query("SELECT LINE,OP,STN,PARTNO FROM ACC_UNITHISTORY WHERE REC_ID = " + his_id.ToString());
                if (dt != null && dt.Rows.Count > 0)
                {
                    string line = dt.Rows[0]["LINE"].ToString();
                    string stn = dt.Rows[0]["STN"].ToString();
                    string partNo = dt.Rows[0]["PARTNO"].ToString();

                    stnProcess.logger.Debug(string.Format("History Rec_ID:{0} Line:{1} Station:{2} PartNo:{3}", his_id, line, stn, partNo));
                    lineData = LineManager.GetLineData(line);
                    bomCfg = lineData.Cfg.BomCfg[partNo];
                    StnCfg stnCfg = lineData.Cfg.StnCfg[stn];
                    if (stnCfg != null)
                        procdatacfg = stnCfg.StnPLCProcDataCfg[bomCfg];

                }
            }

            if (procdatacfg != null && procdatacfg.Count > 0)
            {
                ProcDataCfg[] procDataCfgs = procdatacfg.Values.ToArray();

                for (int index = 0; index < procDataCfgs.Length; ++index)
                {
                    string valueType = "";
                    if (INT_PATTERN.IsMatch(procDataCfgs[index].PLC_Tag))
                        valueType = "int";
                    else if (REAL_PATTERN.IsMatch(procDataCfgs[index].PLC_Tag))
                        valueType = "double";
                    else if (BOOL_PATTERN.IsMatch(procDataCfgs[index].PLC_Tag))
                        valueType = "bool";
                    else if (STRING_PATTERN.IsMatch(procDataCfgs[index].PLC_Tag))
                        valueType = "string";

                    if (his_id <= 0)
                    {
                        double lowLimit = 0, upLimit = 0;
                        if (!string.IsNullOrEmpty(procDataCfgs[index].Low_Limit_STN) && !string.IsNullOrEmpty(procDataCfgs[index].Low_Limit_ADDR))
                        {
                            lowLimit = stnProcess.GetLimitValueWithPLCAddress(lineData, procDataCfgs[index].Low_Limit_STN, bomCfg.PartNo, procDataCfgs[index].Low_Limit_ADDR);
                        }
                        if (!string.IsNullOrEmpty(procDataCfgs[index].Up_Limit_STN) && !string.IsNullOrEmpty(procDataCfgs[index].Up_Limit_ADDR))
                        {
                            upLimit = stnProcess.GetLimitValueWithPLCAddress(lineData, procDataCfgs[index].Up_Limit_STN, bomCfg.PartNo, procDataCfgs[index].Up_Limit_ADDR);
                        }

                        if (procDataCfgs[index].Limits_Type == LimitType.Offset)
                        {
                            double limitSetValue = lowLimit;
                            double limitOffset = upLimit;
                            lowLimit = limitSetValue - limitOffset;
                            upLimit = limitSetValue + limitOffset;
                        }

                        lstProcData.Add(new ClientProcData()
                        {
                            Name = procDataCfgs[index].Name,
                            Description = procDataCfgs[index].Description,
                            LowLimit = lowLimit.ToString(),
                            UpLimit = upLimit.ToString(),
                            ValueType = valueType,
                            Unit = procDataCfgs[index].UM,
                            Address = procDataCfgs[index].PLC_Tag,
                            Position = procDataCfgs[index].Position
                        });
                    }
                    else
                    {
                        string lowLimit = "", upLimit = "", value = "";
                        var dt = DataManager.DBHelper.Query("SELECT VALUE, LOW_LIMIT, UP_LIMIT FROM ACC_PROCDATA_VALUE WHERE UNITHIST_ID=" + his_id.ToString() + " AND DATAID=" + procDataCfgs[index].Rec_ID.ToString());
                        if (dt != null && dt.Rows.Count > 0)
                        {
                            value = dt.Rows[0]["VALUE"].ToString();
                            lowLimit = dt.Rows[0]["LOW_LIMIT"].ToString();
                            upLimit = dt.Rows[0]["UP_LIMIT"].ToString();
                        }

                        lstProcData.Add(new ClientProcData()
                        {
                            Name = procDataCfgs[index].Name,
                            Description = procDataCfgs[index].Description,
                            LowLimit = lowLimit.ToString(),
                            UpLimit = upLimit.ToString(),
                            ValueType = valueType,
                            Unit = procDataCfgs[index].UM,
                            Address = procDataCfgs[index].PLC_Tag,
                            Position = procDataCfgs[index].Position,
                            Value = value
                        });
                    }
                }
            }

            return lstProcData;
        }

        public static List<ClientParttypeData> GetPartTypeData(this StnProcess stnProcess, string partNo)
        {
            List<ClientParttypeData> lstPartdata = new List<ClientParttypeData>();
            PartTyeDataCfg ptdCfg = null;
            DictionaryEx<int, PartTyeDataCfg> datas = stnProcess._data.StnCfg.PartTypeData[partNo];
            if (datas != null)
            {
                foreach (PartTyeDataCfg cfg in datas.Values)
                {
                    lstPartdata.Add(new ClientParttypeData()
                    {
                        Name = cfg.Name,
                        Description = cfg.Description,
                        ValueType = cfg.ValueType.ToString(),
                        Value = cfg.Value,
                        Address = cfg.Address
                    });
                }
            }

            return lstPartdata;
        }
        public static string GetPartTypeDataByPLCTagAddress(this StnProcess stnProcess, string partNo, string plcTag)
        {
            PartTyeDataCfg ptdCfg = null;
            DictionaryEx<int, PartTyeDataCfg> datas = stnProcess._data.StnCfg.PartTypeData[partNo];
            if (datas != null)
                ptdCfg = datas.Values.FirstOrDefault(c => c.Address == plcTag);

            return ptdCfg == null ? string.Empty :
                ((ptdCfg.ValueType == PartTyeDataCfg.PartTyeDataValueType.PLC_STRING || ptdCfg.ValueType == PartTyeDataCfg.PartTyeDataValueType.TEST_STRING) ? ptdCfg.ValueStr : ptdCfg.Value.ToString());
        }

        public static double GetLimitValueWithPLCAddress(this StnProcess stnProcess, LineData lineData, string station, string partNo, string plcAddress)
        {
            plcAddress = plcAddress.ToUpper();
            StnCfg stn = lineData.Cfg.StnCfg[station];
            if (stn == null)
            {
                return 0;
            }
            DictionaryEx<int, PartTyeDataCfg> datas = stn.PartTypeData[partNo];
            if (datas == null)
            {
                return 0;
            }
            Match match;
            int num;
            Regex regex = null;
            PartTyeDataCfg.PartTyeDataValueType type;
            if (plcAddress.IndexOf("INT") != -1)
            {
                type = PartTyeDataCfg.PartTyeDataValueType.PLC_INT;
                regex = INT_PATTERN;
            }
            else if (plcAddress.IndexOf("REAL") != -1)
            {
                type = PartTyeDataCfg.PartTyeDataValueType.PLC_REAL;
                regex = REAL_PATTERN;
            }
            else
            {
                return 0;
            }
            match = regex.Match(plcAddress);
            if (match.Success)
            {
                num = int.Parse(match.Groups[1].Value);
            }
            else
            {
                return 0;
            }
            object value = null;
            foreach (PartTyeDataCfg cfg in datas.Values)
            {
                if (cfg.ValueType != type)
                {
                    continue;
                }
                match = regex.Match(cfg.Address.ToUpper());
                if (match.Success)
                {
                    if (num == int.Parse(match.Groups[1].Value))
                    {
                        value = cfg.Value;
                    }
                }
            }
            if (value == null)
            {
                return 0;
            }
            else
            {
                return (double)value;
            }
        }

        public static ClientPartType OnGetModelByBarcode(this StnProcess stnProcess, string barcode)
        {
            bool bFromOtherLine = false;
            if (stnProcess._data.Variables.ContainsKey("FINDPARTNOFROMOTHERLINE"))
                bFromOtherLine = (bool)stnProcess._data.Variables["FINDPARTNOFROMOTHERLINE"];

            LineData lineData = stnProcess._data.StnCfg.LineCfg.LineData;

            if (bFromOtherLine)
            {
                var dt = DataManager.DBHelper.Query("SELECT Line FROM ACC_UNITSTATUS WHERE UNITSN = '" + barcode + "' AND LINE != '" + lineData.Line + "'");
                if (dt != null && dt.Rows.Count > 0)
                {
                    string line = dt.Rows[0]["Line"].ToString();
                    if (!string.IsNullOrEmpty(line))
                    {
                        lineData = LineManager.GetLineData(line);
                    }
                }
            }
            ClientPartType clientPartType = null;
            WIPUnit unit = UnitDataProcess.GetWIPUnit(lineData, barcode);
            if (unit != null)
            {
                BomCfg bomCfg = lineData.Cfg.BomCfg[unit.PartNo];

                if (bomCfg != null)
                {
                    clientPartType = new ClientPartType()
                                    {
                                        PartTypeId = (int)bomCfg.PartTypeID,
                                        PartNo = bomCfg.PartNo,
                                        Description = bomCfg.DescLocal,
                                        Sequence = bomCfg.Sequence.HasValue ? (int)bomCfg.Sequence : 0
                                    };
                }
            }

            return clientPartType;
        }

        #region WorkOrder工单
        static string SQL_WO_UPDATE = "UPDATE ACC_WORKORDERHEADER SET QUANTITY=QUANTITY+{0} WHERE WONO='{1}' AND PARTNO='{2}'";
        static string SQL_WO_GET = "SELECT * FROM ACC_WORKORDERHEADER WHERE WONO = '{0}'";
        public static int UpdateWorkOrderQuantity(this StnProcess stnProcess, uint partTypeId, int qty)
        {
            qty = qty < 0 ? 0 : qty;
            if (qty > 0)
            {
                string workOrderNo = "WO" + DateTime.Now.ToString("yyyyMMdd");
                DateTime ctime = DateTime.Now;

                BomCfg bomCfg = stnProcess._data.StnCfg.LineCfg.LineData.Cfg.BomCfgByID[partTypeId];

                if (null != bomCfg)
                {
                    return DataManager.DBHelper.Update(string.Format(SQL_WO_UPDATE, qty, workOrderNo, bomCfg.PartNo));
                }
            }

            return 0;
        }

        public static List<ClientWorkOrder> GetWorkOrder(string datetime)
        {
            DataTable dtWO = DataManager.DBHelper.Query(string.Format(SQL_WO_GET, datetime));
            List<ClientWorkOrder> lstWorkOrder = new List<ClientWorkOrder>();
            if (dtWO != null && dtWO.Rows.Count > 0)
            {
                lstWorkOrder = new List<ClientWorkOrder>();
                foreach (DataRow row in dtWO.Rows)
                {
                    lstWorkOrder.Add(new ClientWorkOrder()
                    {
                        ID = row["ID"] is DBNull ? string.Empty : row["ID"].ToString(),
                        WONO = row["WONO"].ToString(),
                        PartNo = row["PartNo"].ToString(),
                        PlanQuantity = row["PlanQuantity"].ToString(),
                        Quantity = row["Quantity"].ToString(),
                        Status = row["Status"].ToString()
                    });
                }
            }

            return lstWorkOrder;
        }

        #endregion

        #region Defect 保存
        static string SQL_DEFECT_INSERT = "INSERT INTO ACC_DEFECT_HISTORY(CYCLEID,LINE,UNITSN,DEFECTLOCALTION,DEFECTLEVEL,DEFECTLEVELDESC,DEFECTTYPE,DEFECTTYPEDESC) " + " VALUES ('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}')";
        //static string SQL_DEFECT_INSERT = "INSERT INTO ACC_DEFECT_HISTORY(CYCLEID,LINE,UNITSN,DEFECTLOCATION,DEFECTLEVEL,DEFECTLEVELDESC,DEFECTTYPE,DEFECTTYPEDESC) VALUES({0}, '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}')";
        /// <summary>
        /// 保存多个客户端选择的失败Defect Level和Defect Type
        /// </summary>
        /// <param name="stnProcess"></param>
        /// <param name="unitSN"></param>
        /// <param name="cycleid"></param>
        /// <param name="lstFailureBits"></param>
        /// <returns>大于0表示成功n个，等于0保存失败</returns>
        public static int AddDefect(this StnProcess stnProcess, string unitSN, int cycleid, List<ClientFailureBit> lstFailureBits)
        {
            int ret = 0;
            var conn = ACC.Data.DataManager.DBHelper.GetConnection(ACC.Util.DB.DBHelper.DEFAULT);
            var trans = conn.BeginTransaction();
            try
            {
                foreach (ClientFailureBit failureBit in lstFailureBits)
                {
                    if (failureBit != null)
                    {
                        BomCfg bomCfg = stnProcess._data.PartNo == null ? null : stnProcess._data.PartNo.BomCfg;
                        var cfg = bomCfg == null ? null : stnProcess._data.StnCfg.StnStatusWordCfg[bomCfg].Values.FirstOrDefault(c => c.Name == failureBit.Name && c.Type == StatusWordType.FailureWord);
                        string[] ary = failureBit.Description.Split('-');
                        string defectLevel = ary != null && ary.Length > 0 ? ary[0] : "";
                        string defectLevelDesc = ary != null && ary.Length > 1 ? ary[1] : "";

                        ret += DataManager.DBHelper.Update(string.Format(SQL_DEFECT_INSERT, new object[] { cycleid, stnProcess._data.StnCfg.LineCfg.Line, unitSN, failureBit.Location, defectLevel, defectLevelDesc, failureBit.Name, cfg == null ? "" : cfg.Description }), new object[0]);
                    }
                }

                trans.Commit();
                return ret;
            }
            catch (Exception ex)
            {
                trans.Rollback();
                stnProcess.logger.Debug(ex.Message + "\r\n" + ex.StackTrace);
            }
            finally
            {
                if (conn != null && conn.State == System.Data.ConnectionState.Open)
                {
                    conn.Close();
                }
                conn = null;
            }

            return 0;
        }
        #endregion
    }
}
